#include <stdbool.h>
//#include "ursax.h"
#include "log.h"
#include "thread-pool.h"

struct thread_pool;
static long int thread_num = 0;

static inline void workers_tracker_begin(struct workers_tracker* tracker)
{
	if (tracker)
		tracker->workers++;
}

static inline void workers_tracker_end(struct workers_tracker* tracker)
{
	if (tracker)
	{
		tracker->workers--;
		if (tracker->workers == 0 && tracker->waiter){
			st_thread_interrupt(tracker->waiter);
		}
	}
}

static void* tp_thread_stub(void* arg)
{
	LOG_DEBUG("a new thread created, total %ld thread", ++thread_num);
	struct thread_control* tc = (struct thread_control*)arg;
	while(true)
	{
		while(tc->do_work == NULL){
			// LOG_DEBUG("do_work is NULL, sleeping");
			st_sleep(-1);
		}
		if (unlikely(tc->do_work == &tp_thread_stub)){
			LOG_DEBUG("a thread exit, do_work == tp_thread_stub");
			break;
		}

		LOG_DEBUG("thread %p begin to work", st_thread_self());
		workers_tracker_begin(tc->tracker);
		tc->do_work(tc->arg);
		workers_tracker_end(tc->tracker);
		tc->do_work = NULL;
		identity_pool_put((struct identity_pool*)tc->tpool, tc);
		LOG_DEBUG("thread %p finished the work", st_thread_self());
	}
	tc->thread = NULL;
	st_sleep(0);
	LOG_DEBUG("a thread exit---, total %ld thread", --thread_num);
	return NULL;
}

void* _tp_ctor()
{
	struct thread_control* tc = (struct thread_control*)zalloc(sizeof(*tc));
	tc->thread = st_thread_create(&tp_thread_stub, tc, false, ST_STACK_SIZE);
	tc->do_work = NULL;
	st_sleep(0);
	return tc;
}

void _tp_dtor(void* arg)
{
	LOG_DEBUG("thread _tp_dtor start");
	struct thread_control* tc = (struct thread_control*)arg;
	st_thread_t th = tc->thread;
	while(tc->do_work){
		LOG_DEBUG("tc->do_work not NULL, wait %p", tc->do_work);
		st_usleep(1000);
	}
	while(tc->thread && (tc->thread != st_thread_self())){
		tc->do_work = &tp_thread_stub;
		st_thread_interrupt(tc->thread);
		LOG_DEBUG("wait tc->thread null, %p", tc->thread);
		st_sleep(0);
	}
	free(tc);
	if(th == st_thread_self()){
		LOG_DEBUG("a thread exit---, total %ld thread", --thread_num);
		st_thread_exit(0);
	}
}

